1use crate::ext::atomic::*;
3use crate::ext::io::*;
4use crate::scripts::base::*;
5use crate::types::*;
6use crate::utils::bit_stream::*;
7use crate::utils::img::*;
8use crate::utils::struct_pack::*;
9use anyhow::Result;
10use msg_tool_macro::*;
11use std::io::{Read, Seek, Write};
12use std::sync::atomic::AtomicBool;
13use std::sync::{Arc, Mutex};
14
15#[derive(Debug)]
16pub struct BgiCBGBuilder {}
18
19impl BgiCBGBuilder {
20 pub const fn new() -> Self {
22 BgiCBGBuilder {}
23 }
24}
25
26impl ScriptBuilder for BgiCBGBuilder {
27 fn default_encoding(&self) -> Encoding {
28 Encoding::Cp932
29 }
30
31 fn build_script(
32 &self,
33 data: Vec<u8>,
34 _filename: &str,
35 _encoding: Encoding,
36 _archive_encoding: Encoding,
37 config: &ExtraConfig,
38 _archive: Option<&Box<dyn Script>>,
39 ) -> Result<Box<dyn Script>> {
40 Ok(Box::new(BgiCBG::new(data, config)?))
41 }
42
43 fn extensions(&self) -> &'static [&'static str] {
44 &[]
45 }
46
47 fn script_type(&self) -> &'static ScriptType {
48 &ScriptType::BGICbg
49 }
50
51 fn is_image(&self) -> bool {
52 true
53 }
54
55 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
56 if buf_len >= 0x10 && buf.starts_with(b"CompressedBG___") {
57 return Some(255);
58 }
59 None
60 }
61
62 fn can_create_image_file(&self) -> bool {
63 true
64 }
65
66 fn create_image_file<'a>(
67 &'a self,
68 data: ImageData,
69 mut writer: Box<dyn WriteSeek + 'a>,
70 _options: &ExtraConfig,
71 ) -> Result<()> {
72 let encoder = CbgEncoder::new(data)?;
73 let data = encoder.encode()?;
74 writer.write_all(&data)?;
75 Ok(())
76 }
77}
78
79#[derive(Debug, StructPack, StructUnpack)]
80struct BgiCBGHeader {
81 width: u16,
82 height: u16,
83 bpp: u32,
84 _unk: u64,
85 intermediate_length: u32,
86 key: u32,
87 enc_length: u32,
88 check_sum: u8,
89 check_xor: u8,
90 version: u16,
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94enum CbgColorType {
95 Bgra32,
96 Bgr24,
97 Grayscale,
98 Bgr565,
99}
100
101fn convert_bgr565_to_bgr24(input: Vec<u8>, width: u16, height: u16) -> ImageData {
102 let pixel_count = width as usize * height as usize;
103 let mut output = Vec::with_capacity(pixel_count * 3);
104
105 for chunk in input.chunks_exact(2) {
106 let pixel = u16::from_le_bytes([chunk[0], chunk[1]]);
107
108 let blue_5bit = (pixel & 0x1) as u8;
109 let green_6bit = ((pixel >> 5) & 0x3) as u8;
110 let red_5bit = ((pixel >> 11) & 0x1) as u8;
111
112 let blue = ((blue_5bit as u16 * 255) / 31) as u8;
113 let green = ((green_6bit as u16 * 255) / 63) as u8;
114 let red = ((red_5bit as u16 * 255) / 31) as u8;
115
116 output.push(blue);
117 output.push(green);
118 output.push(red);
119 }
120
121 ImageData {
122 width: width as u32,
123 height: height as u32,
124 color_type: ImageColorType::Bgr,
125 depth: 8,
126 data: output,
127 }
128}
129
130#[derive(Debug)]
131pub struct BgiCBG {
133 header: BgiCBGHeader,
134 data: MemReader,
135 color_type: CbgColorType,
136}
137
138impl BgiCBG {
139 pub fn new(data: Vec<u8>, _config: &ExtraConfig) -> Result<Self> {
144 let mut reader = MemReader::new(data);
145 let mut magic = [0u8; 16];
146 reader.read_exact(&mut magic)?;
147 if !magic.starts_with(b"CompressedBG___") {
148 return Err(anyhow::anyhow!("Invalid magic: {:?}", magic));
149 }
150 let header = BgiCBGHeader::unpack(&mut reader, false, Encoding::Cp932)?;
151 if header.version > 2 {
152 return Err(anyhow::anyhow!("Unsupported version: {}", header.version));
153 }
154 let color_type = match header.bpp {
155 32 => CbgColorType::Bgra32,
156 24 => CbgColorType::Bgr24,
157 8 => CbgColorType::Grayscale,
158 16 => {
159 if header.version == 2 {
160 return Err(anyhow::anyhow!("Unsupported BPP 16 in version 2"));
161 }
162 CbgColorType::Bgr565
163 }
164 _ => return Err(anyhow::anyhow!("Unsupported BPP: {}", header.bpp)),
165 };
166 Ok(BgiCBG {
167 header,
168 data: reader,
169 color_type,
170 })
171 }
172}
173
174impl Script for BgiCBG {
175 fn default_output_script_type(&self) -> OutputScriptType {
176 OutputScriptType::Json
177 }
178
179 fn default_format_type(&self) -> FormatOptions {
180 FormatOptions::None
181 }
182
183 fn is_image(&self) -> bool {
184 true
185 }
186
187 fn export_image(&self) -> Result<ImageData> {
188 let decoder = CbgDecoder::new(self.data.to_ref(), &self.header, self.color_type)?;
189 Ok(decoder.unpack()?)
190 }
191
192 fn import_image<'a>(
193 &'a self,
194 data: ImageData,
195 mut file: Box<dyn WriteSeek + 'a>,
196 ) -> Result<()> {
197 let encoder = CbgEncoder::new(data)?;
198 let encoded_data = encoder.encode()?;
199 file.write_all(&encoded_data)?;
200 Ok(())
201 }
202}
203
204struct CbgDecoder<'a> {
205 stream: MsbBitStream<MemReaderRef<'a>>,
206 info: &'a BgiCBGHeader,
207 color_type: CbgColorType,
208 key: u32,
209 magic: u32,
210 pixel_size: u8,
211 stride: usize,
212}
213
214impl<'a> CbgDecoder<'a> {
215 fn new(
216 reader: MemReaderRef<'a>,
217 info: &'a BgiCBGHeader,
218 color_type: CbgColorType,
219 ) -> Result<Self> {
220 let magic = 0;
221 let key = info.key;
222 let stream = MsbBitStream::new(reader);
223 let pixel_size = info.bpp as u8 / 8;
224 let stride = info.width as usize * (info.bpp as usize / 8);
225 Ok(CbgDecoder {
226 stream,
227 info,
228 key,
229 magic,
230 color_type,
231 pixel_size,
232 stride,
233 })
234 }
235
236 fn unpack(mut self) -> Result<ImageData> {
237 self.stream.m_input.pos = 0x30;
238 if self.info.version < 2 {
239 return self.unpack_v1();
240 } else if self.info.version == 2 {
241 if self.info.enc_length < 0x80 {
242 return Err(anyhow::anyhow!(
243 "Invalid encoded length: {}",
244 self.info.enc_length
245 ));
246 }
247 return self.unpack_v2();
248 }
249 Err(anyhow::anyhow!("Unknown version: {}", self.info.version))
250 }
251
252 fn unpack_v1(&mut self) -> Result<ImageData> {
253 let leaf_nodes_weight = {
254 let stream = MemReader::new(self.read_encoded()?);
255 let mut stream_ref = stream.to_ref();
256 Self::read_weight_table(&mut stream_ref, 0x100)?
257 };
258 let tree = HuffmanTree::new(&leaf_nodes_weight, false);
259 let mut packed = Vec::with_capacity(self.info.intermediate_length as usize);
260 packed.resize(self.info.intermediate_length as usize, 0);
261 self.huffman_decompress(&tree, &mut packed)?;
262 let buf_size = self.stride * self.info.height as usize;
263 let mut output = Vec::with_capacity(buf_size);
264 output.resize(buf_size, 0);
265 Self::unpack_zeros(&packed, &mut output);
266 self.reverse_average_sampling(&mut output);
267 let color_type = match self.color_type {
268 CbgColorType::Bgra32 => ImageColorType::Bgra,
269 CbgColorType::Bgr24 => ImageColorType::Bgr,
270 CbgColorType::Grayscale => ImageColorType::Grayscale,
271 CbgColorType::Bgr565 => {
272 return Ok(convert_bgr565_to_bgr24(
273 output,
274 self.info.width,
275 self.info.height,
276 ));
277 }
278 };
279 Ok(ImageData {
280 width: self.info.width as u32,
281 height: self.info.height as u32,
282 color_type,
283 depth: 8,
284 data: output,
285 })
286 }
287
288 fn unpack_v2(&mut self) -> Result<ImageData> {
289 let dct_data = self.read_encoded()?;
290 let mut dct = [[0.0f32; 64]; 2];
291 for i in 0..0x80 {
292 dct[i >> 6][i & 0x3f] = dct_data[i] as f32 * DCT_TABLE[i & 0x3f];
293 }
294
295 let base_offset = self.stream.m_input.pos;
296 let tree1 = HuffmanTree::new(
297 &Self::read_weight_table(&mut self.stream.m_input, 0x10)?,
298 true,
299 );
300 let tree2 = HuffmanTree::new(
301 &Self::read_weight_table(&mut self.stream.m_input, 0xB0)?,
302 true,
303 );
304
305 let width = ((self.info.width as i32 + 7) & -8) as i32;
306 let height = ((self.info.height as i32 + 7) & -8) as i32;
307 let y_blocks = height / 8;
308
309 let mut offsets = Vec::with_capacity((y_blocks + 1) as usize);
310 let input_base =
311 (self.stream.m_input.pos + ((y_blocks + 1) as usize * 4) - base_offset) as i32;
312
313 for _ in 0..=y_blocks {
314 let offset = self.stream.m_input.read_i32()?;
315 offsets.push(offset - input_base);
316 }
317
318 let input = self.stream.m_input.data[self.stream.m_input.pos..].to_vec();
319 let pad_skip = ((width >> 3) + 7) >> 3;
320
321 let output_size = (width * height * 4) as usize;
322 let output = vec![0u8; output_size];
323 let output_mutex = Mutex::new(output);
324
325 let decoder = Arc::new(ParallelCbgDecoder {
326 input,
327 output: output_mutex,
328 bpp: self.info.bpp as i32,
329 width,
330 height,
331 tree1,
332 tree2,
333 dct,
334 has_alpha: AtomicBool::new(false),
335 });
336
337 let mut tasks = Vec::new();
338 let mut dst = 0i32;
339
340 for i in 0..y_blocks {
341 let block_offset = offsets[i as usize] + pad_skip;
342 let next_offset = if i + 1 == y_blocks {
343 decoder.input.len() as i32
344 } else {
345 offsets[(i + 1) as usize]
346 };
347 let closure_dst = dst;
348 let decoder_ref = Arc::clone(&decoder);
349
350 let task = std::thread::spawn(move || {
351 decoder_ref.unpack_block(block_offset, next_offset - block_offset, closure_dst)
352 });
353 tasks.push(task);
354 dst += width * 32;
355 }
356
357 if self.info.bpp == 32 {
358 let decoder_ref = Arc::clone(&decoder);
359 let task =
360 std::thread::spawn(move || decoder_ref.unpack_alpha(offsets[y_blocks as usize]));
361 tasks.push(task);
362 }
363
364 for task in tasks {
365 task.join()
366 .map_err(|e| anyhow::anyhow!("Thread join failed: {:?}", e))??;
367 }
368
369 let has_alpha = decoder.has_alpha.qload();
370 let mut output = decoder
371 .output
372 .lock()
373 .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?
374 .clone();
375
376 if !has_alpha {
377 let mut src_idx = 0;
378 let mut dst_idx = 0;
379 for _ in 0..self.info.height {
380 for _ in 0..self.info.width {
381 output[dst_idx] = output[src_idx];
382 output[dst_idx + 1] = output[src_idx + 1];
383 output[dst_idx + 2] = output[src_idx + 2];
384 src_idx += 4;
385 dst_idx += 3;
386 }
387 }
388 output.truncate(dst_idx);
389 }
390
391 let color_type = if has_alpha {
392 ImageColorType::Bgra
393 } else {
394 ImageColorType::Bgr
395 };
396
397 Ok(ImageData {
398 width: decoder.width as u32,
399 height: decoder.height as u32,
400 color_type,
401 depth: 8,
402 data: output,
403 })
404 }
405
406 fn read_encoded(&mut self) -> Result<Vec<u8>> {
407 let mut output = Vec::with_capacity(self.info.enc_length as usize);
408 output.resize(self.info.enc_length as usize, 0);
409 self.stream.m_input.read_exact(&mut output)?;
410 let mut sum = 0u8;
411 let mut xor = 0u8;
412 for i in 0..output.len() {
413 output[i] = output[i].wrapping_sub(self.update_key());
414 sum = sum.wrapping_add(output[i]);
415 xor ^= output[i];
416 }
417 if sum != self.info.check_sum || xor != self.info.check_xor {
418 return Err(anyhow::anyhow!(
419 "Checksum mismatch: sum={}, xor={}",
420 sum,
421 xor
422 ));
423 }
424 Ok(output)
425 }
426
427 fn read_int(input: &mut MemReaderRef<'_>) -> Result<i32> {
428 let mut v = 0;
429 let mut code_length = 0;
430 loop {
431 let code = input.read_i8()?;
432 if code_length >= 32 {
433 return Err(anyhow::anyhow!(
434 "Failed to raed int: code={}, code_length={}",
435 code,
436 code_length
437 ));
438 }
439 v |= ((code & 0x7f) as i32) << code_length;
440 code_length += 7;
441 if code & -128 == 0 {
442 break;
443 }
444 }
445 Ok(v)
446 }
447
448 fn read_weight_table(input: &mut MemReaderRef<'_>, length: usize) -> Result<Vec<u32>> {
449 let mut weights = Vec::with_capacity(length);
450 for _ in 0..length {
451 let weight = Self::read_int(input)? as u32;
452 weights.push(weight);
453 }
454 Ok(weights)
455 }
456
457 fn huffman_decompress(&mut self, tree: &HuffmanTree, output: &mut [u8]) -> Result<()> {
458 for dst in 0..output.len() {
459 output[dst] = tree.decode_token(&mut self.stream)? as u8;
460 }
461 Ok(())
462 }
463
464 fn unpack_zeros(input: &[u8], output: &mut [u8]) {
465 let mut dst = 0;
466 let mut dec_zero = 0;
467 let mut src = 0;
468 while dst < output.len() {
469 let mut code_length = 0;
470 let mut count = 0;
471 let mut code;
472 loop {
473 if src >= input.len() {
474 return;
475 }
476 code = input[src];
477 src += 1;
478 count |= ((code & 0x7f) as usize) << code_length;
479 code_length += 7;
480 if code & 0x80 == 0 {
481 break;
482 }
483 }
484 if dst + count > output.len() {
485 break;
486 }
487 if dec_zero == 0 {
488 if src + count > input.len() {
489 break;
490 }
491 output[dst..dst + count].copy_from_slice(&input[src..src + count]);
492 src += count;
493 } else {
494 for i in 0..count {
495 output[dst + i] = 0;
496 }
497 }
498 dec_zero ^= 1;
499 dst += count;
500 }
501 }
502
503 fn reverse_average_sampling(&self, output: &mut [u8]) {
504 for y in 0..self.info.height {
505 let line = y as usize * self.stride;
506 for x in 0..self.info.width {
507 let pixel = line + x as usize * self.pixel_size as usize;
508 for p in 0..self.pixel_size {
509 let mut avg = 0u32;
510 if x > 0 {
511 avg = avg.wrapping_add(
512 output[pixel + p as usize - self.pixel_size as usize] as u32,
513 );
514 }
515 if y > 0 {
516 avg = avg.wrapping_add(output[pixel + p as usize - self.stride] as u32);
517 }
518 if x > 0 && y > 0 {
519 avg /= 2;
520 }
521 if avg != 0 {
522 output[pixel + p as usize] =
523 output[pixel + p as usize].wrapping_add(avg as u8);
524 }
525 }
526 }
527 }
528 }
529
530 fn update_key(&mut self) -> u8 {
531 let v0 = 20021 * (self.key & 0xffff);
532 let mut v1 = self.magic | (self.key >> 16);
533 v1 = v1
534 .overflowing_mul(20021)
535 .0
536 .overflowing_add(self.key.overflowing_mul(346).0)
537 .0;
538 v1 = (v1 + (v0 >> 16)) & 0xffff;
539 self.key = (v1 << 16) + (v0 & 0xffff) + 1;
540 v1 as u8
541 }
542}
543
544#[derive(Debug)]
545struct HuffmanNode {
546 valid: bool,
547 is_parent: bool,
548 weight: u32,
549 left_index: usize,
550 right_index: usize,
551}
552
553#[derive(Debug)]
554struct HuffmanTree {
555 nodes: Vec<HuffmanNode>,
556}
557
558impl HuffmanTree {
559 fn new(weights: &[u32], v2: bool) -> Self {
560 let mut nodes = Vec::with_capacity(weights.len() * 2);
561 let mut root_node_weight = 0u32;
562 for weight in weights {
563 let node = HuffmanNode {
564 valid: *weight != 0,
565 is_parent: false,
566 weight: *weight,
567 left_index: 0,
568 right_index: 0,
569 };
570 nodes.push(node);
571 root_node_weight = root_node_weight.wrapping_add(*weight);
572 }
573 let mut child_node_index = [0usize; 2];
574 loop {
575 let mut weight = 0u32;
576 for i in 0usize..2usize {
577 let mut min_weight = u32::MAX;
578 child_node_index[i] = usize::MAX;
579 let mut n = 0;
580 if v2 {
581 while n < nodes.len() {
582 if nodes[n].valid {
583 min_weight = nodes[n].weight;
584 child_node_index[i] = n;
585 n += 1;
586 break;
587 }
588 n += 1;
589 }
590 n = n.max(i + 1);
591 }
592 while n < nodes.len() {
593 if nodes[n].valid && nodes[n].weight < min_weight {
594 min_weight = nodes[n].weight;
595 child_node_index[i] = n;
596 }
597 n += 1;
598 }
599 if child_node_index[i] == usize::MAX {
600 continue;
601 }
602 nodes[child_node_index[i]].valid = false;
603 weight = weight.wrapping_add(nodes[child_node_index[i]].weight);
604 }
605 let parent_node = HuffmanNode {
606 valid: true,
607 is_parent: true,
608 left_index: child_node_index[0],
609 right_index: child_node_index[1],
610 weight,
611 };
612 nodes.push(parent_node);
613 if weight >= root_node_weight {
614 break;
615 }
616 }
617 Self { nodes }
618 }
619
620 fn decode_token(&self, stream: &mut MsbBitStream<MemReaderRef<'_>>) -> Result<usize> {
621 let mut node_index = self.nodes.len() - 1;
622 loop {
623 let bit = stream.get_next_bit()?;
624 if !bit {
625 node_index = self.nodes[node_index].left_index;
626 } else {
627 node_index = self.nodes[node_index].right_index;
628 }
629 if !self.nodes[node_index].is_parent {
630 return Ok(node_index);
631 }
632 }
633 }
634
635 fn encode_token(&self, stream: &mut MsbBitWriter<impl Write>, token: usize) -> Result<()> {
636 let mut path = Vec::new();
637 if !self.find_path(self.nodes.len() - 1, token, &mut path) {
638 return Err(anyhow::anyhow!("Token not found in Huffman tree"));
639 }
640 for &bit in path.iter().rev() {
641 stream.put_bit(bit)?;
642 }
643 Ok(())
644 }
645
646 fn find_path(&self, node_index: usize, token: usize, path: &mut Vec<bool>) -> bool {
647 if node_index == usize::MAX {
648 return false;
649 }
650 let node = &self.nodes[node_index];
651 if !node.is_parent {
652 return node_index == token;
653 }
654
655 if self.find_path(node.left_index, token, path) {
656 path.push(false);
657 return true;
658 }
659 if self.find_path(node.right_index, token, path) {
660 path.push(true);
661 return true;
662 }
663 false
664 }
665}
666
667const DCT_TABLE: [f32; 64] = [
668 1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
669 1.38703990, 1.92387950, 1.81225491, 1.63098633, 1.38703990, 1.08979023, 0.75066054, 0.38268343,
670 1.30656302, 1.81225491, 1.70710683, 1.53635550, 1.30656302, 1.02655995, 0.70710677, 0.36047992,
671 1.17587554, 1.63098633, 1.53635550, 1.38268340, 1.17587554, 0.92387950, 0.63637930, 0.32442334,
672 1.00000000, 1.38703990, 1.30656302, 1.17587554, 1.00000000, 0.78569496, 0.54119611, 0.27589938,
673 0.78569496, 1.08979023, 1.02655995, 0.92387950, 0.78569496, 0.61731654, 0.42521504, 0.21677275,
674 0.54119611, 0.75066054, 0.70710677, 0.63637930, 0.54119611, 0.42521504, 0.29289323, 0.14931567,
675 0.27589938, 0.38268343, 0.36047992, 0.32442334, 0.27589938, 0.21677275, 0.14931567, 0.07612047,
676];
677
678const BLOCK_FILL_ORDER: [u8; 64] = [
679 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20,
680 13, 6, 7, 14, 21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51, 58, 59,
681 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63,
682];
683
684struct ParallelCbgDecoder {
685 input: Vec<u8>,
686 output: Mutex<Vec<u8>>,
687 bpp: i32,
688 width: i32,
689 height: i32,
690 tree1: HuffmanTree,
691 tree2: HuffmanTree,
692 dct: [[f32; 64]; 2],
693 has_alpha: AtomicBool,
694}
695
696impl ParallelCbgDecoder {
697 fn unpack_block(&self, offset: i32, length: i32, dst: i32) -> Result<()> {
698 let input = MemReaderRef::new(&self.input[offset as usize..(offset + length) as usize]);
699 let mut reader = MsbBitStream::new(input);
700
701 let block_size = CbgDecoder::read_int(&mut reader.m_input)?;
702 if block_size == -1 {
703 return Ok(());
704 }
705
706 let mut color_data = vec![0i16; block_size as usize];
707 let mut acc = 0i32;
708 let mut i = 0i32;
709
710 while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
711 let count = self.tree1.decode_token(&mut reader)?;
712 if count != 0 {
713 let mut v = reader.get_bits(count as u32)? as i32;
714 if (v >> (count - 1)) == 0 {
715 v = (-1 << count | v) + 1;
716 }
717 acc += v;
718 }
719 color_data[i as usize] = acc as i16;
720 i += 64;
721 }
722
723 if (reader.m_cached_bits & 7) != 0 {
724 reader.get_bits(reader.m_cached_bits & 7)?;
725 }
726
727 i = 0;
728 while i < block_size && reader.m_input.pos < reader.m_input.data.len() {
729 let mut index = 1usize;
730 while index < 64 && reader.m_input.pos < reader.m_input.data.len() {
731 let code = self.tree2.decode_token(&mut reader)?;
732 if code == 0 {
733 break;
734 }
735 if code == 0xf {
736 index += 0x10;
737 continue;
738 }
739 index += code & 0xf;
740 if index >= BLOCK_FILL_ORDER.len() {
741 break;
742 }
743 let bits = code >> 4;
744 let mut v = reader.get_bits(bits as u32)? as i32;
745 if bits != 0 && (v >> (bits - 1)) == 0 {
746 v = (-1 << bits | v) + 1;
747 }
748 color_data[i as usize + BLOCK_FILL_ORDER[index] as usize] = v as i16;
749 index += 1;
750 }
751 i += 64;
752 }
753
754 if self.bpp == 8 {
755 self.decode_grayscale(&color_data, dst)?;
756 } else {
757 self.decode_rgb(&color_data, dst)?;
758 }
759
760 Ok(())
761 }
762
763 fn decode_rgb(&self, data: &[i16], dst: i32) -> Result<()> {
764 let block_count = self.width / 8;
765 let mut dst = dst as usize;
766
767 for i in 0..block_count {
768 let mut src = (i * 64) as usize;
769 let mut ycbcr_block = [[0i16; 3]; 64];
770
771 for channel in 0..3 {
772 self.decode_dct(channel, data, src, &mut ycbcr_block)?;
773 src += (self.width * 8) as usize;
774 }
775
776 let mut output = self
777 .output
778 .lock()
779 .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
780
781 for j in 0..64 {
782 let cy = ycbcr_block[j][0] as f32;
783 let cb = ycbcr_block[j][1] as f32;
784 let cr = ycbcr_block[j][2] as f32;
785
786 let r = cy + 1.402f32 * cr - 178.956f32;
788 let g = cy - 0.34414f32 * cb - 0.71414f32 * cr + 135.95984f32;
789 let b = cy + 1.772f32 * cb - 226.316f32;
790
791 let y = j >> 3;
792 let x = j & 7;
793 let p = (y * self.width as usize + x) * 4 + dst;
794
795 output[p] = Self::float_to_byte(b);
796 output[p + 1] = Self::float_to_byte(g);
797 output[p + 2] = Self::float_to_byte(r);
798 }
799 dst += 32;
800 }
801 Ok(())
802 }
803
804 fn decode_grayscale(&self, data: &[i16], dst: i32) -> Result<()> {
805 let mut src = 0;
806 let block_count = self.width / 8;
807 let mut dst = dst as usize;
808
809 for _ in 0..block_count {
810 let mut ycbcr_block = [[0i16; 3]; 64];
811 self.decode_dct(0, data, src, &mut ycbcr_block)?;
812 src += 64;
813
814 let mut output = self
815 .output
816 .lock()
817 .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
818
819 for j in 0..64 {
820 let y = j >> 3;
821 let x = j & 7;
822 let p = (y * self.width as usize + x) * 4 + dst;
823 let value = ycbcr_block[j][0] as u8;
824
825 output[p] = value;
826 output[p + 1] = value;
827 output[p + 2] = value;
828 }
829 dst += 32;
830 }
831 Ok(())
832 }
833
834 fn unpack_alpha(&self, offset: i32) -> Result<()> {
835 let mut input = MemReaderRef::new(&self.input[offset as usize..]);
836
837 if input.read_i32()? != 1 {
838 return Ok(());
839 }
840
841 let mut dst = 3;
842 let mut ctl = 1i32 << 1;
843
844 let mut output = self
845 .output
846 .lock()
847 .map_err(|e| anyhow::anyhow!("Failed to lock output: {}", e))?;
848
849 while dst < output.len() {
850 ctl >>= 1;
851 if ctl == 1 {
852 ctl = (input.read_u8()? as i32) | 0x100;
853 }
854
855 if (ctl & 1) != 0 {
856 let v = input.read_u16()? as i32;
857 let mut x = v & 0x3f;
858 if x > 0x1f {
859 x |= -0x40;
860 }
861 let mut y = (v >> 6) & 7;
862 if y != 0 {
863 y |= -8;
864 }
865 let count = ((v >> 9) & 0x7f) + 3;
866
867 let src = dst as isize + (x as isize + y as isize * self.width as isize) * 4;
868 if src < 0 || src >= dst as isize {
869 return Ok(());
870 }
871
872 let mut src = src as usize;
873 for _ in 0..count {
874 output[dst] = output[src];
875 src += 4;
876 dst += 4;
877 }
878 } else {
879 output[dst] = input.read_u8()?;
880 dst += 4;
881 }
882 }
883
884 self.has_alpha.qsave(true);
885 Ok(())
886 }
887
888 fn decode_dct(
889 &self,
890 channel: usize,
891 data: &[i16],
892 src: usize,
893 output: &mut [[i16; 3]; 64],
894 ) -> Result<()> {
895 let d = if channel > 0 { 1 } else { 0 };
896 let mut tmp = [[0f32; 8]; 8];
897
898 for i in 0..8 {
899 if data[src + 8 + i] == 0
901 && data[src + 16 + i] == 0
902 && data[src + 24 + i] == 0
903 && data[src + 32 + i] == 0
904 && data[src + 40 + i] == 0
905 && data[src + 48 + i] == 0
906 && data[src + 56 + i] == 0
907 {
908 let t = data[src + i] as f32 * self.dct[d][i];
909 for row in 0..8 {
910 tmp[row][i] = t;
911 }
912 continue;
913 }
914
915 let v1 = data[src + i] as f32 * self.dct[d][i];
916 let v2 = data[src + 8 + i] as f32 * self.dct[d][8 + i];
917 let v3 = data[src + 16 + i] as f32 * self.dct[d][16 + i];
918 let v4 = data[src + 24 + i] as f32 * self.dct[d][24 + i];
919 let v5 = data[src + 32 + i] as f32 * self.dct[d][32 + i];
920 let v6 = data[src + 40 + i] as f32 * self.dct[d][40 + i];
921 let v7 = data[src + 48 + i] as f32 * self.dct[d][48 + i];
922 let v8 = data[src + 56 + i] as f32 * self.dct[d][56 + i];
923
924 let v10 = v1 + v5;
925 let v11 = v1 - v5;
926 let v12 = v3 + v7;
927 let v13 = (v3 - v7) * 1.414213562f32 - v12;
928 let v1 = v10 + v12;
929 let v7 = v10 - v12;
930 let v3 = v11 + v13;
931 let v5 = v11 - v13;
932 let v14 = v2 + v8;
933 let v15 = v2 - v8;
934 let v16 = v6 + v4;
935 let v17 = v6 - v4;
936 let v8 = v14 + v16;
937 let v11 = (v14 - v16) * 1.414213562f32;
938 let v9 = (v17 + v15) * 1.847759065f32;
939 let v10 = 1.082392200f32 * v15 - v9;
940 let v13 = -2.613125930f32 * v17 + v9;
941 let v6 = v13 - v8;
942 let v4 = v11 - v6;
943 let v2 = v10 + v4;
944
945 tmp[0][i] = v1 + v8;
946 tmp[1][i] = v3 + v6;
947 tmp[2][i] = v5 + v4;
948 tmp[3][i] = v7 - v2;
949 tmp[4][i] = v7 + v2;
950 tmp[5][i] = v5 - v4;
951 tmp[6][i] = v3 - v6;
952 tmp[7][i] = v1 - v8;
953 }
954
955 let mut dst = 0;
956 for i in 0..8 {
957 let v10 = tmp[i][0] + tmp[i][4];
958 let v11 = tmp[i][0] - tmp[i][4];
959 let v12 = tmp[i][2] + tmp[i][6];
960 let v13 = tmp[i][2] - tmp[i][6];
961 let v14 = tmp[i][1] + tmp[i][7];
962 let v15 = tmp[i][1] - tmp[i][7];
963 let v16 = tmp[i][5] + tmp[i][3];
964 let v17 = tmp[i][5] - tmp[i][3];
965
966 let v13 = 1.414213562f32 * v13 - v12;
967 let v1 = v10 + v12;
968 let v7 = v10 - v12;
969 let v3 = v11 + v13;
970 let v5 = v11 - v13;
971 let v8 = v14 + v16;
972 let v11 = (v14 - v16) * 1.414213562f32;
973 let v9 = (v17 + v15) * 1.847759065f32;
974 let v10 = v9 - v15 * 1.082392200f32;
975 let v13 = v9 - v17 * 2.613125930f32;
976 let v6 = v13 - v8;
977 let v4 = v11 - v6;
978 let v2 = v10 - v4;
979
980 output[dst][channel] = Self::float_to_short(v1 + v8);
981 output[dst + 1][channel] = Self::float_to_short(v3 + v6);
982 output[dst + 2][channel] = Self::float_to_short(v5 + v4);
983 output[dst + 3][channel] = Self::float_to_short(v7 + v2);
984 output[dst + 4][channel] = Self::float_to_short(v7 - v2);
985 output[dst + 5][channel] = Self::float_to_short(v5 - v4);
986 output[dst + 6][channel] = Self::float_to_short(v3 - v6);
987 output[dst + 7][channel] = Self::float_to_short(v1 - v8);
988 dst += 8;
989 }
990
991 Ok(())
992 }
993
994 fn float_to_short(f: f32) -> i16 {
995 let a = 0x80 + ((f as i32) >> 3);
996 if a <= 0 {
997 0
998 } else if a <= 0xff {
999 a as i16
1000 } else if a < 0x180 {
1001 0xff
1002 } else {
1003 0
1004 }
1005 }
1006
1007 fn float_to_byte(f: f32) -> u8 {
1008 if f >= 255.0 {
1009 0xff
1010 } else if f <= 0.0 {
1011 0
1012 } else {
1013 f as u8
1014 }
1015 }
1016}
1017
1018struct CbgEncoder {
1019 header: BgiCBGHeader,
1020 stream: MemWriter,
1021 img: ImageData,
1022 key: u32,
1023 magic: u32,
1024}
1025
1026impl CbgEncoder {
1027 pub fn new(mut img: ImageData) -> Result<Self> {
1028 if img.depth != 8 {
1029 return Err(anyhow::anyhow!("Unsupported image depth: {}", img.depth));
1030 }
1031 let bpp = match img.color_type {
1032 ImageColorType::Bgr => 24,
1033 ImageColorType::Bgra => 32,
1034 ImageColorType::Grayscale => 8,
1035 ImageColorType::Rgb => {
1036 convert_rgb_to_bgr(&mut img)?;
1037 24
1038 }
1039 ImageColorType::Rgba => {
1040 convert_rgba_to_bgra(&mut img)?;
1041 32
1042 }
1043 };
1044 let key = rand::random();
1045 let header = BgiCBGHeader {
1046 width: img.width as u16,
1047 height: img.height as u16,
1048 bpp,
1049 _unk: 0,
1050 intermediate_length: 0,
1051 key,
1052 enc_length: 0,
1053 check_sum: 0,
1054 check_xor: 0,
1055 version: 1,
1056 };
1057
1058 Ok(CbgEncoder {
1059 header,
1060 stream: MemWriter::new(),
1061 img,
1062 key,
1063 magic: 0,
1064 })
1065 }
1066
1067 pub fn encode(mut self) -> Result<Vec<u8>> {
1068 self.stream.write_all(b"CompressedBG___\0")?;
1069 let header_pos = self.stream.pos;
1070 self.stream.seek(std::io::SeekFrom::Current(0x20))?;
1071
1072 let pixel_size = (self.header.bpp / 8) as usize;
1073 let stride = self.header.width as usize * pixel_size;
1074 let mut sampled_data = self.img.data.clone();
1075 self.average_sampling(&mut sampled_data, stride, pixel_size);
1076
1077 let packed_data = Self::pack_zeros(&sampled_data);
1078 self.header.intermediate_length = packed_data.len() as u32;
1079
1080 let mut frequencies = vec![0u32; 256];
1081 for &byte in &packed_data {
1082 frequencies[byte as usize] += 1;
1083 }
1084 if frequencies.iter().all(|&f| f == 0) {
1085 frequencies[0] = 1;
1086 }
1087
1088 let tree = HuffmanTree::new(&frequencies, false);
1089
1090 let mut weight_writer = MemWriter::new();
1091 for &weight in &frequencies {
1092 Self::write_int(&mut weight_writer, weight as i32)?;
1093 }
1094 let weight_data = weight_writer.into_inner();
1095 self.write_encoded(&weight_data)?;
1096
1097 let mut bit_writer = MsbBitWriter::new(&mut self.stream);
1098 for &byte in &packed_data {
1099 tree.encode_token(&mut bit_writer, byte as usize)?;
1100 }
1101 bit_writer.flush()?;
1102
1103 let final_pos = self.stream.pos;
1104 self.stream.pos = header_pos;
1105 self.header.pack(&mut self.stream, false, Encoding::Cp932)?;
1106 self.stream.pos = final_pos;
1107
1108 Ok(self.stream.into_inner())
1109 }
1110
1111 fn average_sampling(&self, data: &mut [u8], stride: usize, pixel_size: usize) {
1112 for y in (0..self.header.height as usize).rev() {
1113 let line = y * stride;
1114 for x in (0..self.header.width as usize).rev() {
1115 let pixel = line + x * pixel_size;
1116 for p in 0..pixel_size {
1117 let mut avg = 0u32;
1118 let mut count = 0;
1119 if x > 0 {
1120 avg = avg.wrapping_add(data[pixel + p - pixel_size] as u32);
1121 count += 1;
1122 }
1123 if y > 0 {
1124 avg = avg.wrapping_add(data[pixel + p - stride] as u32);
1125 count += 1;
1126 }
1127 if count > 0 {
1128 avg /= count;
1129 }
1130 if avg != 0 {
1131 data[pixel + p] = data[pixel + p].wrapping_sub(avg as u8);
1132 }
1133 }
1134 }
1135 }
1136 }
1137
1138 fn pack_zeros(input: &[u8]) -> Vec<u8> {
1139 let mut output = Vec::new();
1140 let mut i = 0;
1141 let mut is_zero_run = false;
1142
1143 while i < input.len() {
1144 let mut count = 0;
1145 if is_zero_run {
1146 while i + count < input.len() && input[i + count] == 0 {
1147 count += 1;
1148 }
1149 } else {
1150 while i + count < input.len() && input[i + count] != 0 {
1151 count += 1;
1152 }
1153 }
1154
1155 let mut count_buf = Vec::new();
1156 let mut n = count;
1157 loop {
1158 let mut byte = (n & 0x7f) as u8;
1159 n >>= 7;
1160 if n > 0 {
1161 byte |= 0x80;
1162 }
1163 count_buf.push(byte);
1164 if n == 0 {
1165 break;
1166 }
1167 }
1168 output.extend_from_slice(&count_buf);
1169
1170 if !is_zero_run {
1171 output.extend_from_slice(&input[i..i + count]);
1172 }
1173 i += count;
1174 is_zero_run = !is_zero_run;
1175 }
1176 output
1177 }
1178
1179 fn write_int<W: Write>(writer: &mut W, mut value: i32) -> Result<()> {
1180 loop {
1181 let mut b = (value as u8) & 0x7f;
1182 value >>= 7;
1183 if value != 0 {
1184 b |= 0x80;
1185 }
1186 writer.write_u8(b)?;
1187 if value == 0 {
1188 break;
1189 }
1190 }
1191 Ok(())
1192 }
1193
1194 fn write_encoded(&mut self, data: &[u8]) -> Result<()> {
1195 self.header.enc_length = data.len() as u32;
1196 let mut sum = 0u8;
1197 let mut xor = 0u8;
1198 let mut encoded_data = Vec::with_capacity(data.len());
1199 for &byte in data {
1200 let encrypted_byte = byte.wrapping_add(self.update_key());
1201 sum = sum.wrapping_add(byte);
1202 xor ^= byte;
1203 encoded_data.push(encrypted_byte);
1204 }
1205 self.header.check_sum = sum;
1206 self.header.check_xor = xor;
1207 self.stream.write_all(&encoded_data)?;
1208 Ok(())
1209 }
1210
1211 fn update_key(&mut self) -> u8 {
1212 let v0 = 20021 * (self.key & 0xffff);
1213 let mut v1 = self.magic | (self.key >> 16);
1214 v1 = v1
1215 .overflowing_mul(20021)
1216 .0
1217 .overflowing_add(self.key.overflowing_mul(346).0)
1218 .0;
1219 v1 = (v1 + (v0 >> 16)) & 0xffff;
1220 self.key = (v1 << 16) + (v0 & 0xffff) + 1;
1221 v1 as u8
1222 }
1223}